package com.imooc.miaosha.redis;

import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
 * @author simple
 * @version 1.0
 * @date 2018/6/14 15:43
 */
@Service
public class RedisService {
    @Autowired
    RedisConfig redisConfig;

    @Autowired
    JedisPool jedisPool;

    /**
     * 获取当个对象
     */
    public <T> T get(KeyPrefix prefix, String key, Class<T> clazz) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            //生成真正的key
            String realKey = prefix.getPrefix() + key;
            String str = jedis.get(realKey);
            return stringToBean(str, clazz);
        } finally {
            returnToPool(jedis);
        }
    }

    /**
     * 设置对象
     */
    public <T> boolean set(KeyPrefix prefix, String key, T value) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            String str = beanToString(value);
            if (str == null || str.length() <= 0) {
                return false;
            }
            //生成真正的key
            String realKey = prefix.getPrefix() + key;
            int seconds = prefix.expiresSec();
            if (seconds <= 0) {
                jedis.set(realKey, str);
            } else {
                jedis.setex(realKey, seconds, str);
            }
            return true;
        } finally {
            returnToPool(jedis);
        }
    }

    /**
     * 判断key是否存在
     */
    public <T> boolean exists(KeyPrefix prefix, String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            //生成真正的key
            String realKey = prefix.getPrefix() + key;
            return jedis.exists(realKey);
        } finally {
            returnToPool(jedis);
        }
    }

    /**
     * 增加值
     */
    public <T> Long incr(KeyPrefix prefix, String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            //生成真正的key
            String realKey = prefix.getPrefix() + key;
            return jedis.incr(realKey);
        } finally {
            returnToPool(jedis);
        }
    }

    /**
     * 减少值
     */
    public <T> Long decr(KeyPrefix prefix, String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            //生成真正的key
            String realKey = prefix.getPrefix() + key;
            return jedis.decr(realKey);
        } finally {
            returnToPool(jedis);
        }
    }

    public <T> boolean set(String key, T value) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            String valueStr = beanToString(value);
            if (StringUtils.isEmpty(valueStr)) {
                return false;
            }
            jedis.set(key, valueStr);
            return true;
        } finally {
            returnToPool(jedis);
        }
    }

    public <T> T get(String key, Class<T> clazz) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            String keyStr = jedis.get(key);
            return stringToBean(keyStr, clazz);
        } finally {
            returnToPool(jedis);
        }
    }


    @SuppressWarnings("unchecked")
    private <T> T stringToBean(String keyStr, Class<T> clazz) {
        if (null == keyStr) {
            return null;
        }
        if (StringUtils.isEmpty(keyStr)) {
            return null;
        }
        if (null == clazz) {
            return null;
        }
        if (int.class == clazz || Integer.class == clazz) {
            return (T) Integer.valueOf(keyStr);
        } else if (long.class == clazz || Long.class == clazz) {
            return (T) Long.valueOf(keyStr);
        } else if (float.class == clazz || Float.class == clazz) {
            //
            return (T) Float.valueOf(keyStr);
        } else if (double.class == clazz || Double.class == clazz) {
            //
            return (T) Double.valueOf(keyStr);
        } else if (byte.class == clazz || Byte.class == clazz) {
            return (T) Byte.valueOf(keyStr);
        } else if (short.class == clazz || Short.class == clazz) {
            return (T) Short.valueOf(keyStr);
        } else if (String.class == clazz) {
            return (T) String.valueOf(keyStr);
        } else {
            return JSON.toJavaObject(JSON.parseObject(keyStr), clazz);
        }
    }


    private <T> String beanToString(T value) {
        if (null == value) {
            return null;
        }
        Class<?> clazz = value.getClass();
        if (int.class == clazz || Integer.class == clazz) {
            return String.valueOf(clazz);
        } else if (long.class == clazz || Long.class == clazz) {
            return String.valueOf(clazz);
        } else if (float.class == clazz || Float.class == clazz) {
            //
            return String.valueOf(clazz);
        } else if (double.class == clazz || Double.class == clazz) {
            //
            return String.valueOf(clazz);
        } else if (char.class == clazz || Character.class == clazz) {
            //
            return String.valueOf(clazz);
        } else if (byte.class == clazz || Byte.class == clazz) {
            return String.valueOf(clazz);
        } else if (short.class == clazz || Short.class == clazz) {
            return String.valueOf(clazz);
        } else if (String.class == clazz) {
            return (String) value;
        } else {
            return JSON.toJSONString(value);
        }
    }


    private void returnToPool(Jedis jedis) {
        if (null != jedis) {
            jedis.close();
        }
    }

    @Bean
    public JedisPool jedisPoolFactory() {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxTotal(redisConfig.getPoolMaxTotal());
        jedisPoolConfig.setMaxIdle(redisConfig.getPoolMaxIdle());
        jedisPoolConfig.setMaxWaitMillis(redisConfig.getPoolMaxWait());
        return new JedisPool(jedisPoolConfig, redisConfig.getHost(), redisConfig.getPort(),
                redisConfig.getTimeout(), redisConfig.getPassword());
    }
}
